﻿// Original author contact info: Owen Emlen (owene_1998@yahoo.com)
// Note: other individuals may also have contributed to this code
// Project hosted on CodePlex.com as of 1/10/2009 at http://www.codeplex.com/EmlenMud
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Threading;
using BrainTechLLC.ThreadSafeObjects;
using System.Runtime.Serialization;
using System.Reflection;
using System.Diagnostics;

namespace BrainTechLLC
{
    [Serializable]
    [DataContract]
    public class DynamicMethod
    {
        [NonSerialized]
        protected object _lock;

        [DataMember]
        public Method Method { get; set; }

        [DataMember]
        public Type DelegateType { get; set; }

        [NonSerialized]
        protected Delegate _delegate;

        [MethodVisible]
        public static DynamicMethod Create(MethodInfo mi, Type delegateType)
        {
            return Create(mi.DeclaringType.Name, mi.Name, delegateType);
        }

        [MethodVisible]
        public static DynamicMethod Create(string typeName, string methodName, Type delegateType)
        {
            DynamicMethod result = new DynamicMethod()
            {
                Method = new Method(typeName, methodName),
                DelegateType = delegateType
            };

            return result;
        }

        public Delegate MethodDelegate
        {
            get
            {
                if (_delegate == null)
                {
                    if (_lock == null)
                        Interlocked.CompareExchange<object>(ref _lock, new object(), null);

                    lock (_lock)
                    {
                        if (_delegate == null)
                        {
                            try
                            {
                                MethodInfo mi = Method.FindMethod();
                                _delegate = Delegate.CreateDelegate(DelegateType, mi);
                            }
                            catch (Exception ex)
                            {                                
                                Debug.WriteLine(ex.ToString());
                                throw;
                            }
                        }
                    }
                }

                return _delegate;
            }
        }

        public object Invoke(params object[] args)
        {
            return MethodDelegate.DynamicInvoke(args);
        }
    }
}